import socket
import threading
import json
import time
import sqlite3

friend_list = {}  # 当前节点自己的好友列表，结构: {id: {...}}
complete_lists = {}  # 接收到的其他人的好友列表，结构: {sender_ip: [...]}
online_peers = {}  # 在线用户（不管是否是好友），结构: {ip: {...}}
import netifaces

def get_broadcast_addresses():
    import netifaces
    broadcasts = []
    print("=== 网卡广播地址扫描 ===")
    for iface in netifaces.interfaces():
        ifaddresses = netifaces.ifaddresses(iface)
        if netifaces.AF_INET in ifaddresses:
            for link in ifaddresses[netifaces.AF_INET]:
                ip = link.get('addr')
                broadcast = link.get('broadcast')
                if broadcast and not broadcast.startswith("127."):
                    broadcasts.append(broadcast)
                    print(f"[{iface}] IP: {ip}, 广播地址: {broadcast}")
                else:
                    print(f"[{iface}] 跳过无效广播地址: {broadcast}")
    print("==========================")
    return broadcasts


# 获取本机 IP
def get_ip():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.connect(('8.8.8.8', 80))  # 公共IP用于触发本地IP识别
    local_ip = sock.getsockname()[0]
    sock.close()
    return local_ip

# 读取数据库中的好友列表
def get_local_friend_list():
    global friend_list
    with sqlite3.connect("p2p.db", check_same_thread=False) as conn:
        cursor = conn.cursor()
        # 获取好友信息
        cursor.execute("SELECT id, name, ip,timestamp FROM friends")
        for row in cursor.fetchall():
            id_, name, ip,timestamp= row
            friend_list[str(id_)] = {
                "id": id_,
                "name": name,
                "ip": ip,
                "timestamp":timestamp
            }
        return friend_list

#读取用户的群ID
def get_groupid():
    with sqlite3.connect("p2p.db", check_same_thread=False) as conn:
        cursor = conn.cursor()
        # 获取当前用户 ID
        cursor.execute("SELECT id FROM current_user")
        current_id = cursor.fetchone()[0]
        cursor.execute("select groupId from tblGroup where owner=?",(current_id,))
        groupids=cursor.fetchall()
        groupid_list=[]
        for groupid in groupids:
            groupid_list.append(groupid[0])
        return groupid_list
# 向特定 IP 发送 JSON 消息
def send_to_peer(ip, msg_dict):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.sendto(json.dumps(msg_dict).encode(), (ip, 12345))
        s.close()
    except Exception as e:
        print(f"[发送失败] {ip}: {e}")

# 广播 ping 消息
def broadcast_ping():
    with sqlite3.connect("p2p.db", check_same_thread=False) as conn:
        cursor = conn.cursor()
        # 获取当前用户 ID
        cursor.execute("SELECT id FROM current_user")
        current_id = cursor.fetchone()[0]
        # 获取当前用户信息
        cursor.execute("SELECT id, name, ip,host FROM user WHERE id=?", (current_id,))
        row = cursor.fetchone()
        print(row)
        if row:
            id_, name, ip, host = row
            if host:
                cursor.execute("SELECT id FROM user WHERE host=1")
                host_id = cursor.fetchone()[0]
            else:
                host_id = 0
        else:
            print("[错误] 当前用户未找到，跳过广播")
            return  # 或者 raise Exception
        # timestamp = int(time.time() * 1000)    # 毫秒级 Unix 时间戳
        msg = {
            "action": "online_status",
            "id": id_,
            "name": name,
            "ip": ip,
            "timestamp":int(time.time() * 1000),
            "group_id":get_groupid(),
            "host_id":host_id
        }
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
            broadcast_addresses = get_broadcast_addresses()
            print(broadcast_addresses)
            for bcast_ip in broadcast_addresses:
                s.sendto(json.dumps(msg).encode(), (bcast_ip, 12345))
            s.close()
            print("[广播] 已发送 ping")

            # 向23456端口广播（仅online_status类型）
            s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
            s2.sendto(json.dumps(msg).encode(), (bcast_ip, 23456))
            s2.close()
            print ("[广播] 已发送 ping 到 23456 端口")
        except Exception as e:
            print(f"[广播发送失败]: {e}")   

# 定时广播 ping
def periodic_broadcast():
    while True:
        broadcast_ping()
        time.sleep(10)  # 每 10 秒广播一次
#合并字典并且跳过重复的
def merge_friend_lists(target_dict, new_dict):
    for key, value in new_dict.items():
        if key not in target_dict:
            target_dict[key] = value
    return target_dict
# 监听接收所有类型消息
def listen():
    global complete_lists
    print("listen")
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind(('0.0.0.0', 12345))
    # print(get_ip())
    while True:
        data, addr = s.recvfrom(4096)
        try:
            msg = json.loads(data.decode())
        except json.JSONDecodeError:
            continue
        # print(msg)
        msg_type = msg.get("action")
        sender_ip = addr[0]
        # print(sender_ip)
        # print(get_ip())
        if "id" not in msg:
            print(f"[跳过] 收到无 id 字段的消息：{msg}")
            continue  # 安全跳过
        with sqlite3.connect("p2p.db", check_same_thread=False) as conn:
            cursor = conn.cursor()
                # 获取当前用户 ID
            cursor.execute("SELECT id FROM current_user")
            current_id = cursor.fetchone()[0]
            try:
                if current_id == msg["id"]:
                    print("自己发的消息，跳过")
                    continue  # 忽略自己发送的消息
                if msg_type == "friend_list":
                    # complete_lists=merge_friend_lists(complete_lists,msg["friends"])
                    merge_friend_lists(complete_lists,msg["friends"])
                    print(f"[好友列表] 收到来自 {sender_ip} 的好友列表：{msg['friends']}")
                    cursor.execute("SELECT id, ip, timestamp FROM friends")
                    local_friends = {row[0]: {"ip": row[1], "timestamp": row[2]} for row in cursor.fetchall()}

                    for friend_id, friend_info in msg["friends"].items():
                        new_ip = friend_info["ip"]
                        new_timestamp = friend_info["timestamp"]

                        if friend_id in local_friends:
                            local_ts = local_friends[friend_id]["timestamp"]
                            if new_timestamp > local_ts:
                                # 更新 IP 和 timestamp
                                print('更新 IP 和 timestamp')
                                cursor.execute("UPDATE friends SET ip=?, timestamp=? WHERE id=?", (new_ip, new_timestamp, friend_id))
                    conn.commit()
                elif msg_type == "online_status":
                    # print(f"[在线设备] 收到 ping")
                    # print(msg)
                    # print(f"compelist:{complete_lists}")
                    cursor.execute("select id,ip,timestamp from friends")
                    friends=cursor.fetchall()
                    found=False
                    for friend in friends:
                        id,ip,timestamp=friend
                        if id==msg["id"]:
                            print("更新在线状态")
                            cursor.execute("UPDATE friends SET online=1 WHERE id=?", (id,))
                            # if timestamp<msg["timestamp"]:
                            print('更新ip')
                            cursor.execute("UPDATE friends SET ip = ?, timestamp = ? WHERE id = ?",(msg["ip"],msg["timestamp"],id))
                            cursor.execute("UPDATE friends SET host_id=? WHERE id=?", (msg["host_id"], id))
                            conn.commit()
                            break
                    if found==False:
                        print("更新")
                        new_friend = {}
                        new_friend[str(msg["id"])]={
                            "id": msg["id"],
                            "name": msg["name"],
                            "ip": msg["ip"],
                            "timestamp":msg["timestamp"]
                        }
                        # complete_lists=merge_friend_lists(complete_lists,new_friend)
                        merge_friend_lists(complete_lists,new_friend)
                        # print(f"compelist:{complete_lists}")
                        

                else:
                    print(f"[未知消息] 收到未知类型消息：{msg}")
            finally:
                pass
            #     conn.close()
# def offline_checker(timeout=30, interval=5):
#     while True:
#         try:
#             conn = sqlite3.connect("p2p.db", timeout=10, check_same_thread=False)
#             cursor = conn.cursor()
#             current_time = int(time.time() * 1000)
#             cursor.execute("SELECT id, timestamp, online FROM friends")
#             friends = cursor.fetchall()
#             for friend_id, timestamp_val, online in friends:
#                 if online == 1 and current_time - timestamp_val > timeout:
#                     print(f"好友 {friend_id} 超时未响应，设为离线")
#                     cursor.execute("UPDATE friends SET online = 0 WHERE id = ?", (friend_id,))
#             conn.commit()
#             conn.close()
#         except Exception as e:
#             print("掉线检测线程错误:", e)
#         time.sleep(interval)



# 扫描：向所有好友发送自己的好友列表
def scan():
    local_friend_list = get_local_friend_list()

    # 构造消息
    msg = {
        "action": "friend_list",
        "from": get_ip(),
        "friends": local_friend_list
    }

    # 启动监听线程
    threading.Thread(target=listen, daemon=True).start()

    # 启动广播线程（关键）
    threading.Thread(target=periodic_broadcast, daemon=True).start()

    # 启动掉线检测线程
    # threading.Thread(target=offline_checker, daemon=True).start()
    # 向所有好友发送
    for f in local_friend_list.values():
        if f["ip"] != get_ip():
            send_to_peer(f["ip"], msg)
            print(f"[发送] 已发送好友列表给：{f['name']} @ {f['ip']}")
def Get_friendlist():
    global complete_lists
    print("lsit")
    with sqlite3.connect("p2p.db", check_same_thread=False) as conn:
        cursor = conn.cursor()
        # print(f"compelist:{complete_lists}")
        
        # 获取当前用户 ID
        cursor.execute("SELECT id FROM current_user")
        current_id = cursor.fetchone()[0]

        updated_list = {}

        for friend_id, info in complete_lists.items():
            status = 0

            # 情况1：我请求对方，对方未回应
            cursor.execute("""
                SELECT 1 FROM friend_requests
                WHERE owner = ? AND receiver_id = ? AND status = 'pending_request'
                LIMIT 1
            """, (current_id, friend_id))
            if cursor.fetchone():
                status = 1
            else:
                # 情况2：对方向我发出请求，我还未同意 → 忽略此人
                cursor.execute("""
                    SELECT 1 FROM friend_requests
                    WHERE sender_id = ? AND owner = ? AND status = 'pending_accept'
                    LIMIT 1
                """, (friend_id, current_id))
                if cursor.fetchone():
                    print(f"忽略 {friend_id}：对方待我同意")
                    continue  # 跳过，不加入 updated_list

            # 构造带 status 的好友项
            updated_info = dict(info)
            updated_info["status"] = status
            updated_list[friend_id] = updated_info
            print(f"updatelist:{updated_list}")

        # cursor.close()
        # conn.close()
        
        return updated_list
# 主程序入口
if __name__ == "__main__":
    scan()
    while True:
        time.sleep(1)  # 防止主线程退出
        # list=Get_friendlist()
        # print(list)
